iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
自我挑戰組

重新複習JavaScript系列 第 21

[Day -21] Event Loop

  • 分享至 

  • xImage
  •  

今天要講的 Event Loop,看到網路上很多文章都有提到,這是 JS 最獨特的地方,幾乎沒有其他語言有這個特性。

今天這份文章會以Philip Roberts 在 JS Conf 的演講影片 What the heck is the event loop anyway,為主要架構,在搭配其他文章內容,如有說錯還請大家指教!

之所以選這部影片,是因為我第一次接觸 Event Loop就是看這支影片,因為當時AC的作業要寫這篇的心得並發到部落格,當時真的有看沒有懂XDD

Single Threaded(單線程)

"JavaScript 是一種單線程(single-threaded)的程式語言",這表示 JavaScript 在執行時只使用單一的執行緒。這代表它一次只能執行一段程式碼,無法同時處理多個任務。

然而,JavaScript 通常是在瀏覽器或 Node.js 這樣的環境中運行。這些環境提供了一個執行環境(Runtime Environment),包含了其他執行緒,這些執行緒可以處理一些非同步的任務。比如說,當你使用 setTimeout 函式時,JavaScript 引擎會將它交給執行環境的其他部分處理,以便在指定的時間後執行你提供的code。

簡單來說,雖然 JavaScript 自身是單線程的,但是在運行的環境中(如瀏覽器或 Node.js),可以利用其他執行緒來處理非同步的任務,從而實現同時進行多項操作。

Execution Context Stack(執行環境堆疊)

還記得我們前幾章一直有提到的execution context 嗎?

當 JavaScript 程式開始執行時,它會創建一個global execution context(全域執行環境)。在這個global execution context內,如果呼叫了一個函式,就會為該函式創建一個新的execution context,並將其添加到"執行環境堆疊" 的頂部。當函式完成時,它的execution context從堆疊中移除,程式將繼續在在呼叫函式之前的環境中執行。

每個執行環境都有自己的變數和函式宣告空間。這個執行環境堆疊的概念是管理程式範圍和執行順序的關鍵。

由於部分原因無法觀看節錄的畫面,關於執行堆疊(called stack)的片段大家可以到4分40左右開始觀看。
下面是我節錄影片裡,關於執行堆疊(called stack)的片段,相信大家會更了解。

Blocking(阻塞)

這段影片有提到一個詞,Blocking,中文稱作『阻塞』。

他的意思是當我們在執行程式遇到 blocking時,程式的執行就會像卡住一樣等待很久的時間,直到 blocking的操作完成後程式才會繼續執行。

由於部分原因無法觀看節錄的畫面,這部分大家可以到8分10秒左右觀看

這樣會造成用戶體驗非常糟糕,因此JavaScript 鼓勵使用 non-blocking(非阻塞) 的操作,如asynchronous(非同步)編程模型,例如使用 Promise、async/await 或 callbacks 來處理潛在的長時間操作,以保證程式在等待某些操作完成時仍然可以繼續執行其他任務,不會被blocking。

Synchronous/Asynchronous(同步與非同步)

了解了什麼是blocking(阻塞)與non-blocking(非阻塞)後,其實你已經懂了synchronous(同步) 與 asynchronous(非同步),為什麼這麼說呢?因為在Node.js 的官方文件是這麼說的:

Blocking methods execute synchronously and non-blocking methods execute asynchronously.

阻塞的方法會同步地(synchronously)執行,而非阻塞的方法會非同步地(asynchronously)執行

但我相信還是會有很多人跟我一樣,同步不就是同時進行嗎?為什麼我卻只能一次執行一件事。

這就要提到中文翻譯的問題了,但我英文很差這邊就用另一個方式跟大家解釋:

synchronous(同步)

Imgur

Synchronous:餐廳老闆自己從帶位、點餐、煮菜等,一條龍完成所有作業,在完成一組客人後,才能接待下一位客人。

在JavaScript大部分功能都是同步的,而同步的定義是指:程式碼的執行順序,依照由上而下執行,最後才輸出。

優點當然是很好閱讀,但缺點就是效率變很差。

asynchronous(非同步)

Imgur

Asynchronous:餐廳老闆請了不同的人負責各自專門的事情,服務生負責點餐、廚師負責煮飯。在固定的時間內,可以藉由大家的合作,處理多組客人。

在這案例我們可以得知:

  • 非同步機制能加速餐廳運作,更高效率的處理事情!
  • 但非同步的狀況下,不同客人在不同階段需要的服務是不同的,因此員工間可能會產生「等待」的過程。

我們可以做個總結:所謂的「非同步處理」,可以說就是釐清各式各樣的「等待」流程,並且在因「等待」而複雜化的程式流程中,確保程式能正確運作。

詳細的同步非同步我們會在下一篇中跟大家解釋。

非同步處理與堆疊(Async Callback & Call Stack)

在了解同步非同步後,我們回到影片的案例。

在影片裡,演講者用了經典的setTimeout來舉例,讓我們看一下code:

console.log('hi')

setTimeout(function () {
  console.log('there')
}, 5000)

console.log('JSConfEU')

這段code的結果想必大家應該都很清楚,就是:

hi
JSConfEU
there

但是如果我們把setTimeout的時間改成0的時候,結果會是什麼呢?

答案還是:

hi
JSConfEU
there

疑?為什麼setTimeout 的時間已經是0了應該會直接執行啊?

這就是我們今天所要探討的主題:Event Loop!

JS Runtime Environment

我們先來看一張圖:

Imgur

我們前面有提到,JS 引擎底下有三個部分:

  • Memory Heap「 記憶體堆疊」
  • Global Execution Context「全域執行環境」
  • Execution Context Stack「執行環境堆疊」。

但整個瀏覽器並不只是只有一個JS引擎所組成,因為 JS 語言特性屬於單執行緒,同時又為了讓網頁具有像「監聽事件」、「計時」、「 拉第三方API 」這些類似「背景作業」的功能,瀏覽器提供了另外一些部分來達成,分別是:

  1. Web API
  2. Event Queue
  3. Event Table
  4. Event Loop

整個由上述部分,包含 JS 引擎所組成的環境,也稱為 JS Runtime Environment ( JRE )。

我們先來看一下演講者是如何解釋這整個運作,之後我們再來解釋這4個名詞。
備注:setTimeout 5000的解說可看12:50-14:50,整個流程比較詳細

Web API

Web API 是瀏覽器提供的一組介面,讓 JavaScript 可以與瀏覽器進行互動。

剛剛我們知道了瀏覽器並不只是只有一個JS引擎所組成,我們在寫網頁的時候,有一些所謂「內建的」API 如 SetTimeout / setInterval ,這些 API 不存在於 JavaScript 原始碼內,但你仍然可以在開發時直接使用。

因為這些 API 是屬於瀏覽器提供的 Web API 。Web API 並非 JS 引擎的一部分,但他屬於瀏覽器運行流程的一環。

關於 Web API ,舉一些例子:

  • 操作 DOM 節點的 API 如 :document.getElementById
  • AJAX 相關 API 像是:XMLHttpRequest
  • 計時類型的 API ,就像剛剛提到的 setTimeout

這類 Web API 在與 JS 原始碼一起執行的時候,並不會直接影響 JS 主執行環境的運行,而是會運用非同步的方式,瀏覽器會將這些必須等待執行結果的動作,丟給其他部分去執行,讓 JS 引擎可以繼續做他應該做的事情,等到Web API 完成後將相應的回調函式添加到Event Queue中。

Event Queue

在 JavaScript 中,Event Queue 是用來處理非同步事件的一個概念。

當非同步事件(如定時器、DOM 事件、HTTP 請求的回應等)發生時,相關的回調函式會被放入Event Queue中,等待被執行。Event Queue是一個先進先出(FIFO)的資料結構,確保了事件的執行順序。

Event Table

影片中並沒有提到這個,但在<<JS 原力覺醒 >>的鐵人賽文章有提到這個。以下是原文:

Event Table 與 Event Queue 互相搭配的資料集合,他負責記錄在非同步目的達成後,有哪些函式或者事件要被執行,這裡指的非同步目的指的是像計時完畢、API資料獲取完畢、事件被觸發。當我們執行 setTimeout 這個函式時,JS 會把給定的函式與像是倒數的秒數之類的附帶資訊 ( meta data )推送到 Event Table裡面,等到一秒過後(目的達成)該函式就會被正式推送到Event Queue 等待執行。

Event Loop

Event Loop 是一個持續運行的機制,用於監聽 Event Queue 中是否有待執行的回調函式。如果Event Queue 不為空,事件迴圈會將隊列中的回調函式逐一取出執行。Event Loop 確保了 JavaScript 程序在等待非同步操作的同時,主線程仍然可以處理其他任務。

總結:

到這邊大家應該都懂了吧,如果還是不是那麼清楚,我們在把下面這段看完應該就更了解了。
Yes


第一次嘗試用影片來解說,不然這個要解釋流程我又要劃一堆圖了。

如果有違反任何規定請告知我,我會馬上處理!

參考資料:

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

https://yeefun.github.io/event-loop-in-depth/

What the heck is the event loop anyway


上一篇
[Day -20] Closures
下一篇
[Day -22] Promise
系列文
重新複習JavaScript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言